package com.jichaoyun.sys.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jichaoyun.common.enums.MyExceptiontType;
import com.jichaoyun.common.ex.MyException;
import com.jichaoyun.model.entity.Realdata;
import com.jichaoyun.model.entity.StationInfo;

import com.jichaoyun.common.model.PagedResult;

import com.jichaoyun.sys.mapper.LowParaConfigueMapper;
import com.jichaoyun.sys.mapper.RealdataMapper;
import com.jichaoyun.sys.mapper.StationInfoMapper;

import com.jichaoyun.sys.service.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author zhen
* @description 针对表【realData】的数据库操作Service实现
* @createDate 2023-11-16 19:42:41
*/
@Service
public class RealdataServiceImpl extends ServiceImpl<RealdataMapper, Realdata>
    implements IRealdataService {

    @Resource
    private StationInfoMapper stationInfoMapper;

    @Autowired
    private IStationInfoService stationInfoService;

    @Resource
    private RealdataMapper realdataMapper;

    @Resource
    private LowParaConfigueMapper lowParaConfigueMapper;

    @Autowired
    private LimitAlarmService limitAlarmService;

    @Autowired
    private ComErrAlarmService comErrAlarmService;

    @Autowired
    private DoorOpenAlarmService doorOpenAlarmService;

    @Autowired
    private DcAlarmService dcAlarmService;



    @Override
    public Realdata getStationSingleInfoById(Integer station_no) {

        return this.baseMapper.getStationSingleInfoById(station_no);

    }

    @Override
    public List<Map<String,Object>> getRealDataById(Integer station_no) {

        return this.baseMapper.getRealDatabyId(station_no);
    }

    @Override
    public Map<String, List<Float>> getHalfHourRealData(String stationName) {

        //获取当前时间 和 30分钟前的时间 并 格式化
        LocalDateTime dateTime = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String end = formatter.format(dateTime);
        String start = formatter.format(dateTime.minusMinutes(30));

        //根据传入的站点名称找到站点id
        Map<String, List<Float>> result = new HashMap<>();
        LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationInfo::getStationName,stationName);
        Integer stationId = stationInfoService.getOne(wrapper).getStationNo();


        //查找30分钟前到现在的所有数据，倒序排序,只取最近的30条
        LambdaQueryWrapper<Realdata> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(Realdata::getRecordTime,start).lt(Realdata::getRecordTime,end).eq(Realdata::getStation,stationId).orderByDesc(Realdata::getRealId);
        List<Realdata> list = this.baseMapper.selectList(queryWrapper);
        if(list == null){
            throw new MyException(MyExceptiontType.Other,null);
        }

        List<Float> flowList = new ArrayList<>();
        List<Float> tempList = new ArrayList<>();
        List<Float> presList = new ArrayList<>();
        List<Float> freqList = new ArrayList<>();

        //遍历list，将数据分别写入流量、温度、压力、频率四个链表
        for(Realdata item : list){
            flowList.add(item.getFlow());
            tempList.add(item.getTemp());
            presList.add(item.getPres());
            freqList.add(item.getFreq());
        }
        result.put("近30分钟流量",flowList);
        result.put("近30分钟温度",tempList);
        result.put("近30分钟压力",presList);
        result.put("近30分钟频率",freqList);

        return result;
    }


    @Override
    public List<Realdata> getTop5Flow() {
        List<Realdata> datalist =  this.baseMapper.selectTop5Flow();
        return getRealdata(datalist);
    }

    @Override
    public List<Realdata> getTop5Temp() {
        List<Realdata> datalist =  this.baseMapper.selectTop5Temp();
        return getRealdata(datalist);
    }

    @Override
    public List<Realdata> getTop5Pres() {
        List<Realdata> datalist =  this.baseMapper.selectTop5Pres();
        return getRealdata(datalist);
    }

    @Override
    public PagedResult getMultiRealInfovo(Integer pageNo, Integer pageSize) {
        PageHelper.startPage(pageNo,pageSize);
        List<Realdata> multiRealInfoList = this.baseMapper.getMultiRealInfo();


        for (int i=0;i<multiRealInfoList.size();i++) {
            Realdata multiRealInfo = multiRealInfoList.get(i);
            Integer station = multiRealInfo.getStation();
            LambdaQueryWrapper<StationInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StationInfo::getStationNo,station);
            StationInfo staObject = stationInfoMapper.selectOne(wrapper);
            if(staObject == null){
                throw new MyException(MyExceptiontType.Other,null);
//                multiRealInfo.setStation_name("未知站点错误");
            }else {
                multiRealInfo.setStation_name(staObject.getStationName());
            }
        }
        PageInfo<Realdata> pagelist = new PageInfo<>(multiRealInfoList);
        PagedResult result = new PagedResult();
        result.setTotal((int) pagelist.getTotal());
        result.setPages(pagelist.getPages());
        result.setRows(pagelist.getList());
        return result;
    }


    @NotNull
    /**
     * 主要是给realdata的站名赋值
     */
    private List<Realdata> getRealdata(List<Realdata> datalist) {
        for (Realdata realdata : datalist) {
            Integer station_no = realdata.getStation();
            LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(StationInfo::getStationNo,station_no);
            String station_name =  stationInfoMapper.selectOne(lambdaQueryWrapper).getStationName();
            realdata.setStation_name(station_name);
        }
        return datalist;
    }

    /**
     * 查看各项报警占比
     * @return
     */
    @Override
    public Map<String, Long> eachAlarmProportion() {
        Map<String,Long> map = new HashMap<>();

        map.putAll(limitAlarmService.eachAlarmProportion());

        map.putAll(comErrAlarmService.eachAlarmProportion());

        map.putAll(doorOpenAlarmService.eachAlarmProportion());

        map.putAll(dcAlarmService.eachAlarmProportion());

        return map;
    }

    /**
     * 控制最大的序列大小是subsetSize
     * @param originalList
     * @param subsetSize
     * @return
     */
    private  List<Float> getDivSubset(List<Float> originalList, int subsetSize) {
        List<Float> selectedList = new ArrayList<>();

        int divIndex =0;
        for (int i = 0; i < subsetSize; i++) {
            selectedList.add(originalList.get(i));
            divIndex = (int) originalList.size()*i/subsetSize;
        }

        selectedList.add(originalList.get(originalList.size()-1));
        return selectedList;
    }

    /**
     * 对这个区间的时间也进行10等分
     * @param startTime
     * @param endTime
     * @param divisions
     * @return
     */
    private static List<String> divideDateTime(LocalDateTime startTime, LocalDateTime endTime, int divisions) {
        List<String> result = new ArrayList<>();
        long totalMinutes = startTime.until(endTime, java.time.temporal.ChronoUnit.MINUTES);

        for (int i = 0; i < divisions; i++) {
            long minutesToAdd = totalMinutes * i / divisions;
            LocalDateTime dividedDateTime = startTime.plusMinutes(minutesToAdd);

            // 将时间格式化为字符串并添加到结果列表
            String formattedDateTime = dividedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
            result.add(formattedDateTime);
        }

        // 添加结束时间点
        result.add(endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));

        return result;
    }

    /**
     * 管损报表查询-查询右边的图
     * 查找某时间区间内的数据
     * @param stationNo
     * @return
     */
    @Override
    public Map<String, Object> getPeriodLineLossForm(Integer stationNo, LocalDateTime start, LocalDateTime end) {
        HashMap<String,Object> resMap = new HashMap<>();

        List<Realdata> realdataList= realdataMapper.historySelect(stationNo,start,end);
//        System.out.println(realdataList);
        List<Float> pipeLossRateList = new ArrayList<>();
        for (Realdata realdata : realdataList) {
            pipeLossRateList.add(realdata.getPipeLossRate());
        }

        //给前端最多返回这么多的数据，，这里进行均等分割算法
        int desired_count = 600;
        if (pipeLossRateList.size()>desired_count){
            //更新序列
            pipeLossRateList =  getDivSubset(pipeLossRateList,desired_count);
        }

        List<String> timeList = divideDateTime(start,end,10);
        resMap.put("时间序列",timeList);


        List<String> lossList = new ArrayList<>();
        for (Float rate : pipeLossRateList) {
            lossList.add(String.format("%.2f",rate));
            resMap.put("数据序列",lossList);
        }
        return resMap;
    }

    /**
     * 获取24小时以内的日报表
     * @param stationNo
     * @param start
     * @param end
     * @return
     */
    @Override
    public Map<String, Object> get24HourNum(Integer stationNo, LocalDateTime start, LocalDateTime end) {
        HashMap<String, Object> resMap = new HashMap<>();
        ArrayList<String> timeList = new ArrayList<>();
        ArrayList<Float>  flowList = new ArrayList<>();
        Float low = stationInfoMapper.selectById(stationNo).getDownFlow();
        Float high = stationInfoMapper.selectById(stationNo).getUpFlow();

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM.dd HH:mm");

        for(int x =1;x<=24;x++){
            List<Realdata> realdataList1 = realdataMapper.historySelect(stationNo, start, start.plusSeconds(80));
            List<Realdata> realdataList2 = realdataMapper.historySelect(stationNo, start.plusHours(1), start.plusHours(1).plusSeconds(80));
            if(realdataList1.size()==0||realdataList2.size()==0){
                realdataList1 = realdataMapper.historySelect(stationNo, start, start.plusSeconds(600));
                realdataList2 = realdataMapper.historySelect(stationNo, start.plusHours(1), start.plusHours(1).plusSeconds(600));
            }
            if(realdataList1.size()==0||realdataList2.size()==0){
               throw new MyException(MyExceptiontType.DATAERROR1,null);
            }

            flowList.add(realdataList2.get(0).getTotal()-realdataList1.get(0).getTotal());
            timeList.add(start.format(dateTimeFormatter)+"~"+start.plusHours(x).format(dateTimeFormatter));
            start = start.plusHours(1);
        }
        resMap.put("数据",flowList);
        resMap.put("时间序列",timeList);
        resMap.put("低流量阈值",low);
        resMap.put("高流量阈值",high);


        return resMap;
    }

    /**
     * 管损报表查询
     * @param pageNo
     * @param start
     * @param end
     * @param stationNo
     * @return
     */
    @Override
    public PagedResult getLineLossForm(Integer pageNo, LocalDateTime start, LocalDateTime end ,Integer stationNo) {
        HashMap<String,Object> resMap = new HashMap<>();
        List<Map<String,Object>> resMapList = new ArrayList<>();
        PagedResult pagedResult = new PagedResult();

        Integer pageSize = 10;
        Integer offSize = pageSize *(pageNo-1);
        List<Realdata> realdataList = realdataMapper.historySelectPage(pageSize,offSize,stationNo,start,end);

        Integer total = realdataMapper.historySelectCount(stationNo,start,end);
        pagedResult.setPages((int)Math.ceil(total*1.0/pageSize));
        pagedResult.setTotal(total);

        for (Realdata realdata : realdataList) {
            resMap.put("总表流量（t/h)",realdata.getFlow());
            resMap.put("时间",realdata.getRecordTime());
            resMap.put("分表流量(t/h)",realdata.getSubTotalFlow());
            resMap.put("管损(t/h)",realdata.getPipeLoss());
            resMap.put("管损率",String.format("%.4f",realdata.getPipeLossRate()*100));
            resMapList.add(resMap);
        }
        pagedResult.setRows(resMapList);
        return pagedResult;
    }

    public String calculateMinuteLossRareByStation(LocalDateTime time, Integer stationNo ,Float mainFlow){
        //查出其子节点表
        LambdaQueryWrapper<StationInfo> wp = new LambdaQueryWrapper<>();
        wp.eq(StationInfo::getFatherStationNo,stationNo);
        List<StationInfo> divStation= stationInfoMapper.selectList(wp);

        //计算分表的流量和
        Float div_f = 0f;
        LocalDateTime start1 = time.withSecond(0);
        LocalDateTime end1= time.withSecond(0).plusSeconds(59);
        for (StationInfo stationInfo : divStation) {
            LambdaQueryWrapper<Realdata> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.le(Realdata::getRecordTime,end1).ge(Realdata::getRecordTime,start1)
                    .eq(Realdata::getStation,stationInfo.getStationNo()).orderByDesc(Realdata::getRealId);
            Realdata one = realdataMapper.selectOne(wrapper2);
            if (one == null){
                div_f+=0f;
            }else {
                div_f+=one.getFlow();
            }
        }
        return String.format("%.2f",(mainFlow-div_f)*100/mainFlow)+"%";

    }

    @Override
    public Map<String, Object> getTenMinutesLineLossForm(Integer stationNo) {
        LocalDateTime start = LocalDateTime.now().minusMinutes(11);
        HashMap<String, Object> resMap = new HashMap<>();
        LocalDateTime end = LocalDateTime.now();
        LambdaQueryWrapper<Realdata> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.le(Realdata::getRecordTime,end).ge(Realdata::getRecordTime,start)
                .eq(Realdata::getStation,stationNo).orderByDesc(Realdata::getRealId);
        List<Realdata> realdataList = realdataMapper.selectList(wrapper2);
        int i  = 0;
        for (Realdata realdata : realdataList) {
            if(i==10) {
                break;
            }
            LocalDateTime time = realdata.getRecordTime();
            String loss = calculateMinuteLossRareByStation(time, stationNo, realdata.getFlow());

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
            // 格式化时间
            String formattedTime = time.format(formatter);

            resMap.put(formattedTime,loss);
            i++;

        }

        return resMap;
    }




}




